/*
MIT License

Copyright (c) 2022 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов,

https://bmstu.codes/lsx/simodo/loom
*/

#ifndef simodo_loom_Loom
#define simodo_loom_Loom

/** 
 * @file Loom.h
 * @brief Определения для Loom
 */

#include "simodo/loom/Loom_interface.h"
#include "simodo/loom/Fiber_interface.h"
#include "simodo/loom/Feeder_template.h"

#include <mutex>
#include <thread>
#include <atomic>
#include <condition_variable>
#include <functional>

namespace simodo::loom 
{
   /**
    * @brief Воплощение ткацкого станка. 
    * 
    */
    class Loom : public Loom_interface
    {
        std::vector<FiberStructure>         _harbor;
        mutable std::mutex                  _harbor_mutex;

        std::condition_variable             _waiting_condition;
        mutable std::mutex                  _waiting_condition_mutex;

        Feeder_template<Fiber_interface *>  _queue;
        std::condition_variable             _queue_condition;
        mutable std::mutex                  _queue_condition_mutex;

        std::vector<std::thread>            _threads;

        std::atomic_bool                    _need_pause = false;
        std::atomic_bool                    _need_stop  = false;

        Fiber_interface *                   _causer     = nullptr;
        std::condition_variable *           _debug_condition = nullptr;

        void route();

    public:
        Loom(int threads_required = 0);
        ~Loom();

        void setDebugCondition(std::condition_variable * debug_condition)
        {
            _debug_condition = debug_condition;
        }

    // Loom_interface
    public:
        virtual bool                dock(   Fiber_interface * p_fiber, 
                                            bool need_delete=false, 
                                            Fiber_interface * p_parent=nullptr,
                                            FiberStatus status=FiberStatus::Delayed,
                                            const std::string & name={})        override;
        virtual bool                stretch(Fiber_interface * p_fiber)          override;
        virtual bool                pause()                                     override;
        virtual bool                resume()                                    override;
        /// \note 'final' is fix PVS Studio err V1053 Calling the 'stop' virtual function in 
        /// the destructor may lead to unexpected result at runtime.
        virtual bool                stop()                                      override final;
        /// \note 'final' is fix PVS Studio err V1053 Calling the 'finish' virtual function in 
        /// the destructor may lead to unexpected result at runtime.
        virtual void                finish()                                    override final;

        virtual bool                paused()                            const   override;
        virtual size_t              shuttles()                          const   override;
        virtual Fiber_interface *   causer()                                    override;
        virtual std::vector<FiberStructure> fibers()                    const   override;

    protected:
        void waitAll();
        void waitFiber(const Fiber_interface * p_fiber);
        void cut(Fiber_interface * p_fiber);

    protected:
        bool setFiberStatus(Fiber_interface * p_fiber, FiberStatus status);
        void setFiberComplete(Fiber_interface * p_fiber);
        void checkChildsComplete(Fiber_interface * p_fiber);
        bool setFiberToWait(Fiber_interface * p_fiber);
        bool docked(const Fiber_interface * p_fiber) const { return find(p_fiber).p_fiber != nullptr; }
        FiberStructure find(const Fiber_interface * p_fiber) const;
        bool existFlowedChilds_unsafe(const Fiber_interface * p_fiber) const;
    };

}

#endif // simodo_loom_Loom
